home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / social / facebook / objects2.pyo (.txt) < prev   
Python Compiled Bytecode  |  2008-10-13  |  40KB  |  1,212 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from objects import NewsfeedItem
  6. from util.observe.observablelist import ObservableList
  7. from util import do, clamp, try_this, strftime_u
  8. import os.path as os
  9. from util.cacheable import cproperty
  10. from fbutil import one_per_day, one_per_x_per_day
  11. from collections import defaultdict
  12. from common import pref
  13. from util.cacheable import get_cache_root
  14. import time
  15. import datetime
  16. from datetime import date
  17. from util import tag
  18. from xml.sax.saxutils import escape
  19. import logging
  20. log = logging.getLogger('facebook.objects2')
  21. import traceback
  22. EXPIRE_TO_DISK = False
  23.  
  24. def safe(s):
  25.     return None if s is not None else s
  26.  
  27.  
  28. def writetag(f, t):
  29.     return f.write(t._to_xml().encode('utf-8', 'ignore'))
  30.  
  31.  
  32. class Status(NewsfeedItem):
  33.     
  34.     def __init__(self, uid, name, time, message):
  35.         NewsfeedItem.__init__(self)
  36.         self.uid = uid
  37.         self.name = name
  38.         self.time = time
  39.         self.message = message
  40.  
  41.     
  42.     def get_link(self):
  43.         return 'http://www.facebook.com/profile.php?id=%d' % self.uid
  44.  
  45.     
  46.     def get_text(self):
  47.         return u'%s %s' % (self.name, self.message)
  48.  
  49.  
  50.  
  51. class SelfStatus(object):
  52.     
  53.     def __init__(self, name = None, message = None):
  54.         self.name = name
  55.         self.message = message
  56.  
  57.     
  58.     def formated_name(self):
  59.         if self.name is None:
  60.             return _('This User')
  61.         
  62.         return self.name.encode('xml')
  63.  
  64.     formated_name = property(formated_name)
  65.     
  66.     def formated_message(self):
  67.         if not self.message:
  68.             return _('has no status')
  69.         
  70.         return self.message.encode('xml')
  71.  
  72.     formated_message = property(formated_message)
  73.  
  74.  
  75. class Profile(NewsfeedItem):
  76.     
  77.     def __init__(self, uid, name, time, sex):
  78.         NewsfeedItem.__init__(self)
  79.         self.uid = uid
  80.         self.name = name
  81.         self.sex = sex
  82.         self.time = time
  83.  
  84.     
  85.     def get_link(self):
  86.         return 'http://www.facebook.com/profile.php?id=%d&highlight' % self.uid
  87.  
  88.     
  89.     def get_text(self):
  90.         return u'%s updated %s profile' % (self.name, self.his_her_their)
  91.  
  92.  
  93.  
  94. class Album(NewsfeedItem):
  95.     
  96.     def __init__(self, uid, owner_name, time, aid, name, link):
  97.         NewsfeedItem.__init__(self)
  98.         self.time = time
  99.         self.link = link
  100.         self.aid = aid
  101.         self.name = name
  102.         self.owner = uid
  103.         self.owner_name = owner_name
  104.  
  105.     
  106.     def set_link(self, link):
  107.         self._link = link
  108.  
  109.     
  110.     def get_link(self):
  111.         return self._link
  112.  
  113.     
  114.     def get_text(self):
  115.         return u'%s added new photos to album - %s' % (self.owner_name, self.name)
  116.  
  117.     
  118.     def uid(self):
  119.         return self.owner
  120.  
  121.     uid = property(uid)
  122.  
  123.  
  124. class WallNoteCount2(object):
  125.     
  126.     def __init__(self, user, time_ = None):
  127.         self.time = None if time_ is not None else int(user.anon)
  128.         self.uid = int(user.uid)
  129.         self.name = str(user.name)
  130.         self.wall_count = None if user.wall_count else -1
  131.         self.notes_count = None if user.notes_count else -1
  132.  
  133.  
  134.  
  135. class FriendsWall(NewsfeedItem):
  136.     
  137.     def __init__(self, uid, name, time, count):
  138.         NewsfeedItem.__init__(self)
  139.         self.uid = uid
  140.         self.name = name
  141.         self.time = time
  142.         self.wall_count = count
  143.  
  144.     
  145.     def get_link(self):
  146.         return 'http://www.facebook.com/wall.php?id=%d' % self.uid
  147.  
  148.     
  149.     def get_text(self):
  150.         return u'%s has a new wall post' % self.name
  151.  
  152.  
  153.  
  154. class FriendsNotes(NewsfeedItem):
  155.     
  156.     def __init__(self, uid, name, time, count):
  157.         NewsfeedItem.__init__(self)
  158.         self.uid = uid
  159.         self.name = name
  160.         self.time = time
  161.         self.notes_count = count
  162.  
  163.     
  164.     def get_link(self):
  165.         return 'http://www.facebook.com/notes.php?id=%d' % self.uid
  166.  
  167.     
  168.     def get_text(self):
  169.         return u'%s added a new note' % self.name
  170.  
  171.  
  172.  
  173. class Tagged(NewsfeedItem):
  174.     
  175.     def __init__(self, album, name, link):
  176.         NewsfeedItem.__init__(self)
  177.         self.time = max((lambda .0: for t in .0:
  178. t)(album.itervalues()))
  179.         self.count = len(album)
  180.         self.album_name = name
  181.         self.link = link
  182.  
  183.     
  184.     def set_link(self, link):
  185.         self._link = link
  186.  
  187.     
  188.     def get_link(self):
  189.         return self._link
  190.  
  191.     
  192.     def get_text(self):
  193.         return u'You were tagged in %s photos in album %s' % (self.count, self.album_name)
  194.  
  195.  
  196.  
  197. class Wall(NewsfeedItem):
  198.     
  199.     def __init__(self, uid, time, count):
  200.         NewsfeedItem.__init__(self)
  201.         self.uid = uid
  202.         self.time = time
  203.         self.wall_count = count
  204.  
  205.     
  206.     def get_link(self):
  207.         return 'http://www.facebook.com/wall.php?id=%d' % self.uid
  208.  
  209.     
  210.     def get_text(self):
  211.         return u'You have a new wall post'
  212.  
  213.  
  214.  
  215. class CombinedFriendsWall(NewsfeedItem):
  216.     
  217.     def __init__(self, seq_of_walls):
  218.         self.walls = list(seq_of_walls)
  219.  
  220.     
  221.     def num_visible(self):
  222.         return pref('facebook.combined_wall.num_visible', 5, int)
  223.  
  224.     num_visible = property(num_visible)
  225.     
  226.     def names(self):
  227.         return sorted((lambda .0: for wall in .0:
  228. wall.name)(self.walls))
  229.  
  230.     
  231.     def visible_walls(self):
  232.         if len(self.walls) - self.num_visible < 2:
  233.             return self.walls
  234.         else:
  235.             return self.walls[:self.num_visible]
  236.  
  237.     
  238.     def number_more(self):
  239.         if len(self.walls) - self.num_visible < 2:
  240.             return 0
  241.         else:
  242.             return len(self.walls) - self.num_visible
  243.  
  244.     
  245.     def get_text(self):
  246.         names = self.names()
  247.         return u', '.join(names[:-1]) + u' and ' + names[-1] + u' have new wall posts'
  248.  
  249.     
  250.     def time(self):
  251.         return self.walls[0].time
  252.  
  253.     time = property(time)
  254.  
  255.  
  256. class CombinedFriendsNotes(NewsfeedItem):
  257.     
  258.     def __init__(self, seq_of_notes):
  259.         self.notes = list(seq_of_notes)
  260.  
  261.     
  262.     def names(self):
  263.         return sorted((lambda .0: for note in .0:
  264. note.name)(self.notes))
  265.  
  266.     
  267.     def get_text(self):
  268.         names = self.names()
  269.         return u', '.join(names[:-1]) + u' and ' + names[-1] + u' wrote new notes'
  270.  
  271.     
  272.     def time(self):
  273.         return self.notes[0].time
  274.  
  275.     time = property(time)
  276.  
  277.  
  278. def by_time(o):
  279.     return o.time
  280.  
  281.  
  282. class User(object):
  283.     
  284.     def __init__(self, uid, nf, fb):
  285.         self.nf = nf
  286.         self.fb = fb
  287.         self.uid = int(uid)
  288.         self.name = None
  289.         self.sex = None
  290.         self.statuses = { }
  291.         self.profiles = set()
  292.         self.albums = defaultdict(dict)
  293.         self.wall_counts = { }
  294.         self.notes_counts = { }
  295.         self.tags = defaultdict(dict)
  296.         self.birthday = None
  297.         self.birthyear = None
  298.  
  299.     
  300.     def __repr__(self):
  301.         return '<User %r %d>' % (self.name, self.uid)
  302.  
  303.     
  304.     def __getstate__(self):
  305.         d = dict(vars(self))
  306.         d.pop('fb')
  307.         d.pop('nf')
  308.         d.pop('birthday', None)
  309.         d.pop('birthyear', None)
  310.         return d
  311.  
  312.     
  313.     def __setstate__(self, d):
  314.         self.birthday = None
  315.         self.birthyear = None
  316.         self.__dict__.update(d)
  317.  
  318.     
  319.     def cache_path(self):
  320.         return self.fb.cache_dir + str(hash(self.uid)) + '.dat'
  321.  
  322.     cache_path = property(cache_path)
  323.     
  324.     def practice_counts(self):
  325.         wn_count = self.next_counts
  326.         if wn_count.notes_count >= 0:
  327.             n = self.notes_counts
  328.             
  329.             try:
  330.                 newest = max(n.iterkeys())
  331.                 if n[newest] < wn_count.notes_count:
  332.                     return True
  333.             except ValueError:
  334.                 return False
  335.             except:
  336.                 None<EXCEPTION MATCH>ValueError
  337.             
  338.  
  339.         None<EXCEPTION MATCH>ValueError
  340.         return False
  341.  
  342.     
  343.     def counts(self, wn_count):
  344.         self.next_counts = wn_count
  345.         if wn_count.birthday:
  346.             
  347.             try:
  348.                 today = datetime.date.today()
  349.                 
  350.                 try:
  351.                     bday = time.strptime(wn_count.birthday, '%B %d, %Y')
  352.                     self.birthyear = bday.tm_year
  353.                 except ValueError:
  354.                     bday = time.strptime(wn_count.birthday, '%B %d')
  355.                     self.birthyear = None
  356.  
  357.                 bday2 = datetime.date(today.year, bday.tm_mon, bday.tm_mday)
  358.                 if bday2 < today:
  359.                     bday2 = datetime.date(today.year + 1, bday.tm_mon, bday.tm_mday)
  360.                 
  361.                 self.birthday = bday2
  362.             except Exception:
  363.                 e = None
  364.                 self.birthday = None
  365.                 self.birthyear = None
  366.                 getLogger = getLogger
  367.                 import logging
  368.                 log = getLogger('facebook.birthdays')
  369.                 log.error('failed to parse: %r because %r', wn_count.birthday, e)
  370.             except:
  371.                 None<EXCEPTION MATCH>Exception
  372.             
  373.  
  374.         None<EXCEPTION MATCH>Exception
  375.  
  376.     
  377.     def roll_back_counts(self):
  378.         if hasattr(self, 'next_counts'):
  379.             del self.next_counts
  380.         
  381.  
  382.     
  383.     def commit_counts(self):
  384.         if hasattr(self, 'next_counts'):
  385.             wn_count = self.next_counts
  386.             del self.next_counts
  387.             self.name = unicode(wn_count.name)
  388.             if wn_count.wall_count >= 0:
  389.                 w = self.wall_counts
  390.                 if w:
  391.                     newest = max(w.iterkeys())
  392.                     if w[newest] < wn_count.wall_count:
  393.                         w[wn_count.time] = wn_count.wall_count
  394.                     elif w[newest] > wn_count.wall_count:
  395.                         w[newest] = wn_count.wall_count
  396.                     
  397.                 else:
  398.                     w[wn_count.time] = wn_count.wall_count
  399.                 self.wall_counts = w
  400.             
  401.             if wn_count.notes_count >= 0:
  402.                 n = self.notes_counts
  403.                 if n:
  404.                     newest = max(n.iterkeys())
  405.                     if n[newest] < wn_count.notes_count:
  406.                         n[wn_count.time] = wn_count.notes_count
  407.                     elif n[newest] > wn_count.notes_count:
  408.                         n[newest] = wn_count.notes_count
  409.                     
  410.                 else:
  411.                     n[wn_count.time] = wn_count.notes_count
  412.                 self.notes_counts = n
  413.             
  414.         
  415.  
  416.     
  417.     def status(self, user):
  418.         self.name = unicode(user.name)
  419.         s = self.statuses
  420.         
  421.         try:
  422.             s[int(user.status.time)] = unicode(user.status.message)
  423.         except ValueError:
  424.             traceback.print_exc()
  425.             log.info('status.time was probably empty')
  426.             return None
  427.  
  428.         self.statuses = s
  429.  
  430.     
  431.     def newest_status(self):
  432.         if self.statuses:
  433.             return self.statuses[max(self.statuses.iterkeys())]
  434.         
  435.  
  436.     
  437.     def profile(self, profile):
  438.         p = self.profiles
  439.         self.name = unicode(profile.name)
  440.         self.sex = unicode(profile.sex)
  441.         p.add((int(profile.profile_update_time), self.practice_counts()))
  442.         self.profiles = p
  443.  
  444.     
  445.     def album(self, album):
  446.         a = self.albums
  447.         time = int(album.modified)
  448.         link = unicode(album.link)
  449.         aid = int(album.aid)
  450.         name = unicode(album.name)
  451.         alb = a[aid]
  452.         alb['name'] = name
  453.         alb['link'] = link
  454.         if 'times' in alb:
  455.             alb['times'].append(time)
  456.         else:
  457.             alb['times'] = [
  458.                 time]
  459.         self.albums = a
  460.  
  461.     
  462.     def tag(self, photo):
  463.         t = self.tags
  464.         alb = t[int(photo.aid)]
  465.         pid = int(photo.pid)
  466.         created = int(photo.created)
  467.         now = int(photo.anon)
  468.         if pid not in alb:
  469.             if created > self.nf.last_tag_time and created < now:
  470.                 alb[pid] = created
  471.             else:
  472.                 alb[pid] = now
  473.         
  474.         self.tags = t
  475.  
  476.     
  477.     def needed_alb_ids(self, ago):
  478.         unknown_alb_ids = set(self.tags.keys()) - set(self.albums.keys())
  479.         if unknown_alb_ids:
  480.             for aid in list(unknown_alb_ids):
  481.                 
  482.                 try:
  483.                     if max(self.tags[aid].values()) < ago:
  484.                         unknown_alb_ids.remove(aid)
  485.                 continue
  486.                 except ValueError:
  487.                     unknown_alb_ids.remove(aid)
  488.                     continue
  489.                 
  490.  
  491.             
  492.         
  493.         return unknown_alb_ids
  494.  
  495.     
  496.     def report(self, now):
  497.         safename = safe(self.name)
  498.         if self.uid == int(self.fb.uid):
  499.             mywalls = [ Wall(self.uid, time, count) for time, count in sorted(self.wall_counts.iteritems())[1:] ]
  500.             mywalls = one_per_day(mywalls, key = by_time)
  501.             return mywalls
  502.         elif self.name is not None:
  503.             statuses = _[2]
  504.             albums = []
  505.             for aid, alb in self.albums.iteritems():
  506.                 name = alb['name']
  507.                 link = alb['link']
  508.                 for time in alb.get('times', []):
  509.                     albums.append(Album(self.uid, safename, time, aid, safe(name), link))
  510.                 
  511.             
  512.             albums = one_per_x_per_day(albums, (lambda o: o.aid), by_time)
  513.             profiles = _[3]
  514.             profiles = one_per_day(profiles, key = by_time)
  515.             walls = [ FriendsWall(self.uid, safename, time, count) for time, count in sorted(self.wall_counts.iteritems())[1:] ]
  516.             walls = one_per_day(walls, key = by_time)
  517.             new_walls = []
  518.             update_before = self.fb.update_before
  519.             for wall in walls:
  520.                 t = update_before(wall.time)
  521.                 if t is not None and wall.time - t < pref('facebook.newsfeed.min_wall_interval', 172800):
  522.                     new_walls.append(wall)
  523.                     continue
  524.                 []
  525.             
  526.             walls = new_walls
  527.             notes = [ FriendsNotes(self.uid, safename, time, count) for time, count in sorted(self.notes_counts.iteritems())[1:] ]
  528.         
  529.         tags = []
  530.         zerodate = date.fromtimestamp(0)
  531.         for aid, alb in self.tags.iteritems():
  532.             days = defaultdict(dict)
  533.             for pid, time_ in alb.iteritems():
  534.                 days[date.fromtimestamp(time_)][pid] = time_
  535.             
  536.             for day, album in days.iteritems():
  537.                 if day != zerodate:
  538.                     if aid in self.albums:
  539.                         al = self.albums[aid]
  540.                         tags.append(Tagged(album, safe(al['name']), al['link']))
  541.                     
  542.                 aid in self.albums
  543.             
  544.         
  545.         return statuses + profiles + albums + walls + notes + tags
  546.  
  547.     
  548.     def expire_profiles(self, x, pop = False):
  549.         retval = []
  550.         for profile in list(self.profiles):
  551.             if profile[0] < x:
  552.                 retval.append(profile)
  553.                 if pop:
  554.                     self.profiles.discard(profile)
  555.                 
  556.             pop
  557.         
  558.         return retval
  559.  
  560.     
  561.     def expire_statuses(self, x, pop = False):
  562.         retval = []
  563.         for t, status in list(self.statuses.items()):
  564.             if t < x:
  565.                 retval.append((t, status))
  566.                 if pop:
  567.                     self.statuses.pop(t)
  568.                 
  569.             pop
  570.         
  571.         return retval
  572.  
  573.     
  574.     def expire_albums(self, x, pop = False):
  575.         retval = []
  576.         for aid, alb in list(self.albums.items()):
  577.             for t in list(alb['times']):
  578.                 if t < x:
  579.                     retval.append((t, aid, alb['name'], alb['link']))
  580.                     if pop:
  581.                         alb['times'].remove(t)
  582.                     
  583.                 pop
  584.             
  585.             if not alb['times']:
  586.                 self.albums.pop(aid)
  587.                 continue
  588.         
  589.         return retval
  590.  
  591.     
  592.     def expire_wall_counts(self, x, pop = False):
  593.         temp = dict(self.wall_counts)
  594.         skeys = sorted(temp.iterkeys())
  595.         logkeys = (filter,)((lambda o: o < x), skeys)
  596.         nologkeys = set(skeys) - set(logkeys)
  597.         if logkeys:
  598.             expired = (dict,)((lambda .0: for key in .0:
  599. (key, temp[key]))(logkeys[:-1]))
  600.         else:
  601.             expired = { }
  602.         unexpired = (dict,)((lambda .0: for key in .0:
  603. (key, temp[key]))(nologkeys))
  604.         if pop:
  605.             for key in expired.iterkeys():
  606.                 del self.wall_counts[key]
  607.             
  608.         
  609.         return (expired, unexpired)
  610.  
  611.     
  612.     def expire_notes_counts(self, x, pop = False):
  613.         temp = dict(self.notes_counts)
  614.         skeys = sorted(temp.iterkeys())
  615.         logkeys = (filter,)((lambda o: o < x), skeys)
  616.         nologkeys = set(skeys) - set(logkeys)
  617.         if logkeys:
  618.             expired = (dict,)((lambda .0: for key in .0:
  619. (key, temp[key]))(logkeys[:-1]))
  620.         else:
  621.             expired = { }
  622.         unexpired = (dict,)((lambda .0: for key in .0:
  623. (key, temp[key]))(nologkeys))
  624.         if pop:
  625.             for key in expired.iterkeys():
  626.                 del self.notes_counts[key]
  627.             
  628.         
  629.         return (expired, unexpired)
  630.  
  631.  
  632.  
  633. class UserDict(dict):
  634.     
  635.     def __getitem__(self, key):
  636.         
  637.         try:
  638.             return dict.__getitem__(self, key)
  639.         except KeyError:
  640.             retval = User(key, self.nf, self.fb)
  641.             dict.__setitem__(self, key, retval)
  642.             return retval
  643.  
  644.  
  645.     
  646.     def __repr__(self):
  647.         return '<UserDict [%r] %s>' % (vars(self), dict.__repr__(self))
  648.  
  649.  
  650.  
  651. class ZeroTime(object):
  652.     time = 0
  653.  
  654.  
  655. class NewsFeed2(ObservableList):
  656.     
  657.     def __repr__(self):
  658.         return object.__repr__(self)
  659.  
  660.     
  661.     def __init__(self, fb):
  662.         self.fb = fb
  663.         self.initialized = False
  664.         ObservableList.__init__(self)
  665.         self.fbtime = int(time.time())
  666.         self.clock = self.fbtime
  667.         self.self_status = None
  668.  
  669.     
  670.     def post_login_init(self):
  671.         self.initialized = True
  672.         users = self.users
  673.         users.nf = self
  674.         users.fb = self.fb
  675.         for val in users.values():
  676.             val.nf = self
  677.             val.fb = self.fb
  678.         
  679.         self.users = users
  680.  
  681.     
  682.     def cache_crypt(self):
  683.         return self.fb.cache_crypt
  684.  
  685.     cache_crypt = property(cache_crypt)
  686.     users = cproperty(UserDict, box = dict, unbox = UserDict, user = True)
  687.     uids = cproperty(list, user = True)
  688.     last_tag_time = cproperty(0, user = True)
  689.     
  690.     def now(self):
  691.         now = int(time.time())
  692.         return (now - self.clock) + self.fbtime
  693.  
  694.     now = property(now)
  695.     
  696.     def cache_path(self):
  697.         return os.path.join(self.fb.cache_dir, 'newsfeed.dat')
  698.  
  699.     cache_path = property(cache_path)
  700.     
  701.     def update_statuses(self, statuses):
  702.         (do,)((lambda .0: for status in .0:
  703. self.users[int(status.uid)].status(status))(statuses))
  704.  
  705.     
  706.     def commit_counts(self):
  707.         do((lambda .0: for user in .0:
  708. user.commit_counts())(self.users.itervalues()))
  709.  
  710.     
  711.     def roll_back_counts(self):
  712.         do((lambda .0: for user in .0:
  713. user.roll_back_counts())(self.users.itervalues()))
  714.  
  715.     
  716.     def most_recent_status_time(self):
  717.         
  718.         try:
  719.             maxtime = max((lambda .0: for user in .0:
  720. for time in user.statuses:
  721. time)(self.users.itervalues()))
  722.         except ValueError:
  723.             maxtime = -1
  724.  
  725.         return maxtime
  726.  
  727.     most_recent_status_time = property(most_recent_status_time)
  728.     
  729.     def update_profiles(self, profiles):
  730.         (do,)((lambda .0: for profile in .0:
  731. self.users[int(profile.uid)].profile(profile))(profiles))
  732.  
  733.     
  734.     def most_recent_profile_time(self):
  735.         
  736.         try:
  737.             maxtime = max((lambda .0: for user in .0:
  738. for time in user.profiles:
  739. time[0])(self.users.itervalues()))
  740.         except ValueError:
  741.             maxtime = -1
  742.  
  743.         return maxtime
  744.  
  745.     most_recent_profile_time = property(most_recent_profile_time)
  746.     
  747.     def update_albums(self, albums):
  748.         (do,)((lambda .0: for album in .0:
  749. self.users[int(album.owner)].album(album))(albums))
  750.  
  751.     
  752.     def most_recent_album_time(self):
  753.         
  754.         try:
  755.             maxtime = max((lambda .0: for user in .0:
  756. for album in user.albums.itervalues():
  757. for time in album['times']:
  758. time)(self.users.itervalues()))
  759.         except ValueError:
  760.             maxtime = -1
  761.  
  762.         return maxtime
  763.  
  764.     most_recent_album_time = property(most_recent_album_time)
  765.     
  766.     def needed_alb_ids(self):
  767.         ago = self.ago
  768.         return (sum,)((lambda .0: for user in .0:
  769. list(user.needed_alb_ids(ago)))(self.users.itervalues()), [])
  770.  
  771.     
  772.     def update_counts(self, counts):
  773.         if len(counts):
  774.             self.fbtime = counts[0].time
  775.             self.clock = int(time.time())
  776.             (do,)((lambda .0: for count in .0:
  777. self.users[int(count.uid)].counts(count))(counts))
  778.         
  779.  
  780.     
  781.     def update_tags(self, photos):
  782.         if len(photos):
  783.             (do,)((lambda .0: for photo in .0:
  784. self.users[int(photo.owner)].tag(photo))(photos))
  785.             self.last_tag_time = int(photos[0].anon)
  786.         
  787.  
  788.     
  789.     def rebuild(self):
  790.         importance = {
  791.             Album: 30,
  792.             Profile: 40,
  793.             Status: 50,
  794.             Tagged: 60,
  795.             FriendsWall: 70,
  796.             FriendsNotes: 80,
  797.             Wall: 90,
  798.             CombinedFriendsWall: 100 }
  799.         
  800.         def c(o1, o2):
  801.             if cmp(o1.time, o2.time):
  802.                 return cmp(o1.time, o2.time)
  803.             
  804.             if type(o1) in importance and type(o2) in importance:
  805.                 return int(clamp(importance[type(o1)] - importance[type(o2)], -1, 1))
  806.             
  807.             return 0
  808.  
  809.         stuff = sorted(sum((lambda .0: for user in .0:
  810. user.report('foo'))(self.users.values()), []), cmp = c, reverse = True)
  811.         newstuff = []
  812.         while stuff:
  813.             item = stuff.pop(0)
  814.             if not isinstance(item, FriendsWall):
  815.                 newstuff.append(item)
  816.                 continue
  817.             
  818.             to_combine = []
  819.             while True:
  820.                 to_combine.append(item)
  821.                 
  822.                 try:
  823.                     item = stuff.pop(0)
  824.                     if not item.time == to_combine[0].time and isinstance(item, FriendsWall) and stuff:
  825.                         stuff.insert(0, item)
  826.                         break
  827.                 continue
  828.                 break
  829.                 continue
  830.  
  831.             if len(to_combine) > 1:
  832.                 newstuff.append(CombinedFriendsWall(to_combine))
  833.                 continue
  834.             newstuff.append(to_combine[0])
  835.         stuff = newstuff
  836.         newstuff = []
  837.         while stuff:
  838.             item = stuff.pop(0)
  839.             if not isinstance(item, FriendsNotes):
  840.                 newstuff.append(item)
  841.                 continue
  842.             
  843.             to_combine = []
  844.             while True:
  845.                 to_combine.append(item)
  846.                 
  847.                 try:
  848.                     item = stuff.pop(0)
  849.                     if not item.time == to_combine[0].time and isinstance(item, FriendsNotes) and stuff:
  850.                         stuff.insert(0, item)
  851.                         break
  852.                 continue
  853.                 break
  854.                 continue
  855.  
  856.             if len(to_combine) > 1:
  857.                 newstuff.append(CombinedFriendsNotes(to_combine))
  858.                 continue
  859.             newstuff.append(to_combine[0])
  860.         newest_status = self.users[self.fb.uid].newest_status()
  861.         if not newest_status:
  862.             newest_status = None
  863.         
  864.         self.self_status = SelfStatus(self.users[self.fb.uid].name, newest_status)
  865.         self[:] = newstuff
  866.         self.uids = self.users.keys()
  867.         self.users = self.users
  868.  
  869.     
  870.     def birthdays(self):
  871.         for user in self.users.itervalues():
  872.             if user.birthday is not None:
  873.                 yield (user, user.birthday)
  874.                 continue
  875.         
  876.  
  877.     
  878.     def sorted_birthdays(self):
  879.         return sorted(self.birthdays(), key = (lambda obj: obj[1]))
  880.  
  881.     
  882.     def top_birthdays(self):
  883.         bdays_ret = []
  884.         i = 0
  885.         bdays = iter(self.sorted_birthdays())
  886.         while i < pref('facebook.newsfeed.num_birthdays', 5):
  887.             
  888.             try:
  889.                 (user, _bday) = bdays.next()
  890.                 if user.name:
  891.                     bdays_ret.append((user.name, strftime_u(user.birthday, '%B %d')))
  892.             except StopIteration:
  893.                 break
  894.  
  895.             i += 1
  896.         return bdays_ret
  897.  
  898.     top_birthdays = property(top_birthdays)
  899.     
  900.     def __iter__(self):
  901.         stuff = self[:]
  902.         last = False
  903.         now = self.now
  904.         today = date.fromtimestamp(now)
  905.         yesterday = date.fromtimestamp(now - 86400)
  906.         ago = self.ago
  907.         times = sorted(self.fb.update_times, reverse = True)
  908.         timebefore = None if times else 0
  909.         uid_filters = [ int(num) for num in pref('facebook.newsfeed.user_filter', []) ]
  910.         max_items = pref('facebook.newsfeed.max_items', default = 50, type = int)
  911.         num_items = 0
  912.         for thing in stuff:
  913.             if hasattr(thing, 'uid') and thing.uid in uid_filters:
  914.                 continue
  915.             elif thing.time < ago:
  916.                 continue
  917.             elif not self.fb.filters['feed'].get(type(thing).__name__, True):
  918.                 continue
  919.             elif isinstance(thing, CombinedFriendsWall) and not self.fb.filters['feed'].get('FriendsWall', True):
  920.                 continue
  921.             elif isinstance(thing, CombinedFriendsNotes) and not self.fb.filters['feed'].get('FriendsNotes', True):
  922.                 continue
  923.             
  924.             timeafter = timebefore
  925.             while timebefore > thing.time:
  926.                 timeafter = timebefore
  927.                 if times:
  928.                     timebefore = times.pop(0)
  929.                     continue
  930.                 timebefore = 0
  931.             if timeafter - timebefore > 1800 and timebefore > 0:
  932.                 thing.correct_time = False
  933.             
  934.             this = date.fromtimestamp(thing.time)
  935.             if not last and this != today:
  936.                 yield None
  937.             
  938.             if not last and this == today:
  939.                 pass
  940.             elif last == this:
  941.                 pass
  942.             elif this == yesterday:
  943.                 yield 'Yesterday'
  944.             else:
  945.                 yield strftime_u(this, pref('facebook.newsfeed.dateformat', '%B %d'))
  946.             yield thing
  947.             num_items += 1
  948.             last = this
  949.         
  950.  
  951.     
  952.     def ago(self):
  953.         maxage = pref('facebook.newsfeed.maxage', 172800)
  954.         maxage = (try_this,)((lambda : int(maxage)), 172800)
  955.         now = self.now
  956.         ago = None if maxage > 0 else 0
  957.         return ago
  958.  
  959.     ago = property(ago)
  960.     
  961.     def logfile(self, day, fn):
  962.         logfile = get_cache_root() / self.fb.cache_dir / strftime_u(day, '%Y-%m-%d') / fn
  963.         if not logfile.parent.exists():
  964.             logfile.parent.makedirs()
  965.         
  966.         return logfile
  967.  
  968.     
  969.     def expire_statuses(self, ago, pop = False):
  970.         for user in self.users.itervalues():
  971.             for t, status in user.expire_statuses(ago, pop):
  972.                 yield (t, (user.uid, status))
  973.             
  974.         
  975.  
  976.     
  977.     def _cleanup_statuses(self, ago):
  978.         days = defaultdict(list)
  979.         for status in self.expire_statuses(ago):
  980.             days[date.fromtimestamp(status[0])].append(status)
  981.         
  982.         for day, statuses in days.iteritems():
  983.             logfile = self.logfile(day, 'statuses.xml')
  984.             statuses.sort()
  985.             
  986.             try:
  987.                 f = _[2]
  988.                 for uid, status in statuses:
  989.                     s = tag('user')
  990.                     s.uid = uid
  991.                     s.status.message = status
  992.                     s.status.time = t
  993.                     writetag(f, s)
  994.             finally:
  995.                 pass
  996.  
  997.         
  998.  
  999.     
  1000.     def expire_profiles(self, ago, pop = False):
  1001.         for user in self.users.itervalues():
  1002.             uid = user.uid
  1003.             for t in user.expire_profiles(ago, pop):
  1004.                 yield (t, uid)
  1005.             
  1006.         
  1007.  
  1008.     
  1009.     def _cleanup_profiles(self, ago):
  1010.         days = defaultdict(list)
  1011.         for profile in self.expire_profiles(ago):
  1012.             days[date.fromtimestamp(profile[0][0])].append(profile)
  1013.         
  1014.         for day, profiles in days.iteritems():
  1015.             logfile = self.logfile(day, 'profiles.xml')
  1016.             profiles.sort()
  1017.             
  1018.             try:
  1019.                 f = _[2]
  1020.                 for t, hidden in profiles:
  1021.                     uid = None
  1022.                     p = tag('user')
  1023.                     p.uid = uid
  1024.                     p.hidden = hidden
  1025.                     p.profile_update_time = t
  1026.                     writetag(f, p)
  1027.             finally:
  1028.                 pass
  1029.  
  1030.         
  1031.  
  1032.     
  1033.     def expire_wall_counts(self, ago, pop = False):
  1034.         for user in self.users.itervalues():
  1035.             uid = user.uid
  1036.             for t, count in user.expire_wall_counts(ago, pop)[0].iteritems():
  1037.                 yield (t, (uid, count))
  1038.             
  1039.         
  1040.  
  1041.     
  1042.     def _cleanup_wall_counts(self, ago):
  1043.         days = defaultdict(list)
  1044.         for wcount in self.expire_wall_counts(ago):
  1045.             days[date.fromtimestamp(wcount[0])].append(wcount)
  1046.         
  1047.         for day, counts in days.iteritems():
  1048.             logfile = self.logfile(day, 'wall_counts.xml')
  1049.             counts.sort()
  1050.             
  1051.             try:
  1052.                 f = _[2]
  1053.                 for uid, count in counts:
  1054.                     c = tag('user')
  1055.                     c.uid = uid
  1056.                     c.wall_count = count
  1057.                     c.time = t
  1058.                     writetag(f, c)
  1059.             finally:
  1060.                 pass
  1061.  
  1062.         
  1063.  
  1064.     
  1065.     def expire_notes_counts(self, ago, pop = False):
  1066.         for user in self.users.itervalues():
  1067.             uid = user.uid
  1068.             for t, count in user.expire_notes_counts(ago, pop)[0].iteritems():
  1069.                 yield (t, (uid, count))
  1070.             
  1071.         
  1072.  
  1073.     
  1074.     def _cleanup_notes_counts(self, ago):
  1075.         days = defaultdict(list)
  1076.         for ncount in self.expire_notes_counts(ago):
  1077.             days[date.fromtimestamp(ncount[0])].append(ncount)
  1078.         
  1079.         for day, counts in days.iteritems():
  1080.             logfile = self.logfile(day, 'notes_counts.xml')
  1081.             counts.sort()
  1082.             
  1083.             try:
  1084.                 f = _[2]
  1085.                 for uid, count in counts:
  1086.                     c = tag('user')
  1087.                     c.uid = uid
  1088.                     c.notes_count = count
  1089.                     c.time = t
  1090.                     writetag(f, c)
  1091.             finally:
  1092.                 pass
  1093.  
  1094.         
  1095.  
  1096.     
  1097.     def expire_albums(self, ago, pop = False):
  1098.         for user in self.users.itervalues():
  1099.             uid = user.uid
  1100.             for t, aid, name, link in user.expire_albums(ago, pop):
  1101.                 yield (t, (uid, aid, name, link))
  1102.             
  1103.         
  1104.  
  1105.     
  1106.     def _cleanup_albums(self, ago):
  1107.         days = defaultdict(list)
  1108.         for album in self.expire_albums(ago):
  1109.             days[date.fromtimestamp(album[0])].append(album)
  1110.         
  1111.         for day, albums in days.iteritems():
  1112.             logfile = self.logfile(day, 'album_updates.xml')
  1113.             albums.sort()
  1114.             
  1115.             try:
  1116.                 f = _[2]
  1117.                 for uid, aid, name, link in albums:
  1118.                     a = tag('album')
  1119.                     a.aid = aid
  1120.                     a.owner = uid
  1121.                     a.name = name
  1122.                     a.link = link
  1123.                     a.modified = t
  1124.                     writetag(f, a)
  1125.             finally:
  1126.                 pass
  1127.  
  1128.         
  1129.  
  1130.     
  1131.     def _cleanup(self):
  1132.         if not self.initialized:
  1133.             return None
  1134.         
  1135.         ago = self.ago
  1136.         print 'cleaning up before:', ago
  1137.         
  1138.         try:
  1139.             if EXPIRE_TO_DISK:
  1140.                 self._cleanup_statuses(ago)
  1141.         except IOError:
  1142.             print 'IOERROR'
  1143.  
  1144.         do(self.expire_statuses(ago, True))
  1145.         
  1146.         try:
  1147.             if EXPIRE_TO_DISK:
  1148.                 self._cleanup_profiles(ago)
  1149.         except IOError:
  1150.             print 'IOERROR'
  1151.  
  1152.         do(self.expire_profiles(ago, True))
  1153.         
  1154.         try:
  1155.             if EXPIRE_TO_DISK:
  1156.                 self._cleanup_wall_counts(ago)
  1157.         except IOError:
  1158.             print 'IOERROR'
  1159.  
  1160.         do(self.expire_wall_counts(ago, True))
  1161.         
  1162.         try:
  1163.             if EXPIRE_TO_DISK:
  1164.                 self._cleanup_notes_counts(ago)
  1165.         except IOError:
  1166.             print 'IOERROR'
  1167.  
  1168.         do(self.expire_notes_counts(ago, True))
  1169.         
  1170.         try:
  1171.             if EXPIRE_TO_DISK:
  1172.                 self._cleanup_albums(ago)
  1173.         except IOError:
  1174.             print 'IOERROR'
  1175.  
  1176.         do(self.expire_albums(ago, True))
  1177.         self.users = self.users
  1178.         a = None if not list(self) else repr(list(self))
  1179.         self._cleanup_update_times()
  1180.         self.rebuild()
  1181.         b = None if a is None else repr(list(self))
  1182.  
  1183.     
  1184.     def _set_of_times(self):
  1185.         s = set()
  1186.         for user in self.users.itervalues():
  1187.             s.update(user.statuses.iterkeys())
  1188.             s.update((lambda .0: for prof in .0:
  1189. prof[0])(user.profiles))
  1190.             for album in user.albums.values():
  1191.                 s.update(album.get('times', []))
  1192.             
  1193.             s.update(user.notes_counts.keys())
  1194.             s.update(user.wall_counts.keys())
  1195.             for alb in user.tags.values():
  1196.                 s.update(alb.values())
  1197.             
  1198.         
  1199.         return s
  1200.  
  1201.     
  1202.     def _cleanup_update_times(self):
  1203.         fb = self.fb
  1204.         current_known_dates = fb.newsfeed._set_of_times()
  1205.         indexes_before = (lambda x: x != -1)([]([], [ fb.idx_before(x) for x in current_known_dates ]))
  1206.         latest = fb.update_times[-100:]
  1207.         surround = []([ fb.update_times[x:x + 2] for x in indexes_before ], [])
  1208.         finished = sorted(set(surround + latest))
  1209.         fb.update_times = finished
  1210.  
  1211.  
  1212.